//
// Created by songpingwang on 25-7-4.
//

#ifndef UDATABASE_H
#define UDATABASE_H

#include <string>
#include <map>
#include <utility>
#include <vector>
#include <functional>
#include <algorithm>
#include <regex>
#include <tuple>
#include <unordered_set>
#include <type_traits>
#include "../thirdparty/ctre-unicode.hpp"
#include <string>
#include <string_view>
#include "../thirdparty/utf8.h"


#ifndef TIME_FUNCTION
#define TIME_FUNCTION(func)                                                 \
    do {                                                                    \
        auto start = std::chrono::high_resolution_clock::now();             \
        func;                                                               \
        auto end = std::chrono::high_resolution_clock::now();               \
        std::chrono::duration<double> duration = end - start;               \
        std::cout << #func << " cost time: " << duration.count() << " seconds" << std::endl; \
    } while (0)
#endif


#ifndef PRINT_REF_VEC
#define PRINT_REF_VEC(vec) \
    do { \
        std::cout << #vec << ": ["; \
        for (size_t i = 0; i < (vec).size(); ++i) { \
            std::cout << (vec)[i].get(); \
            if (i < (vec).size() - 1) { \
                std::cout << ", "; \
            } \
        } \
        std::cout << "]" << std::endl; \
    } while (0)
#endif


#ifndef MAYBE_USE
#define MAYBE_USE  [[maybe_unused]] [[nodiscard]]
#define VOID_USE   [[maybe_unused]]
#endif


#ifdef _WIN32
#ifndef UFrame_API_DLL
#define UFrame_API __declspec(dllexport)
#else
#define UFrame_API __declspec(dllimport)
#endif
#else
#define UFrame_API
#endif


namespace NDFrame {

    template <auto>
    struct always_false : std::false_type {};

    template<typename T>
    MAYBE_USE int to_int(T value) {
        return static_cast<int>(value);
    }

    enum class Field {
        IDX,
        X0,
        Y0,
        X1,
        Y1,
        WIDTH,
        HEIGHT,
        PAGE,
        FLAGS,
        TEXT,
        TEXT_SEP
    };

    struct DataItem {
        int idx;
        int x0;
        int y0;
        int x1;
        int y1;
        int width;
        int height;
        int page;
        int flags;
        std::string text;
        std::string text_sep;

        DataItem() : idx(0), x0(0), y0(0), x1(0), y1(0), width(0), height(0), page(0), flags(0) {
            text.reserve(32);
            text_sep.reserve(32);
        }

        DataItem(const int i, const int x, const int y, const int x1, const int y1, const int w, const int h, const int pg, const int flg,
            std::string str, std::string str_sep = u8"")
                : idx(i), x0(x), y0(y), x1(x1), y1(y1), width(w), height(h), page(pg), flags(flg), text(std::move(str)),
                  text_sep(std::move(str_sep)) {
            text.reserve(32);
            text_sep.reserve(32);
        }

        MAYBE_USE auto
        values() const -> std::tuple<const int &, const int &, const int &, const int &, const int &, const int &, const int &, const int &, const int &,  const std::string &, const std::string &> {
            return std::tie(idx, x0, y0, x1, y1, width, height, page, flags, text, text_sep);
        }

        template<Field field>
        MAYBE_USE constexpr const auto& ValueField() const {
            if constexpr (field == Field::IDX) return idx;
            if constexpr (field == Field::X0) return x0;
            if constexpr (field == Field::Y0) return y0;
            if constexpr (field == Field::X1) return x1;
            if constexpr (field == Field::Y1) return y1;
            if constexpr (field == Field::WIDTH) return width;
            if constexpr (field == Field::HEIGHT) return height;
            if constexpr (field == Field::PAGE) return page;
            if constexpr (field == Field::FLAGS) return flags;
            if constexpr (field == Field::TEXT) return text;
            if constexpr (field == Field::TEXT_SEP) return text_sep;
        }

        template<Field field>
        constexpr auto& ValueField() {
                if constexpr (field == Field::IDX) return idx;
                if constexpr (field == Field::X0) return x0;
                if constexpr (field == Field::Y0) return y0;
                if constexpr (field == Field::X1) return x1;
                if constexpr (field == Field::Y1) return y1;
                if constexpr (field == Field::WIDTH) return width;
                if constexpr (field == Field::HEIGHT) return height;
                if constexpr (field == Field::PAGE) return page;
                if constexpr (field == Field::FLAGS) return flags;
                if constexpr (field == Field::TEXT) return text;
                if constexpr (field == Field::TEXT_SEP) return text_sep;
            }
    };


    class UFrame_API UDataBase {
    public:
        using VecItemPtr = std::vector<DataItem *>;

        virtual ~UDataBase() = default;

        MAYBE_USE virtual size_t size() const = 0;

        MAYBE_USE virtual bool empty() const = 0;

        MAYBE_USE virtual DataItem *getItemPtr() const = 0;

        MAYBE_USE virtual DataItem &back() = 0;

        MAYBE_USE virtual DataItem &front() = 0;
        VOID_USE virtual void print() const = 0;

        /*
        *   判断ZDataFrame的text字段是否在field字符串集合中
        *   - 返回值：
        *     std::vector<size_t>& indices     返回符合条件的索引
        *     VecItemPtr& pointers 返回符合条件的ZDataFrame的行指针
        *     ZDataFrame& dataframe            返回符合条件的ZDataFrame(深复制)
        */

        /*
        * 对ZDataFrame进行第二次过滤（具体过滤函数：传入具体数值）
        * loc_regex            返回查找值是否为空, 第一个参数inout_ptr【输入输出】为再筛选DataItem的地址
        * loc_[regex,_xyxy]    返回查找值是否为空, 第一个参数inout_ptr【输入输出】为再筛选DataItem的地址,筛选条件[regex, (>x0,y0; <x1,y1)]
        * loc_[regex,_x0x1]    返回查找值是否为空, 第一个参数inout_ptr【输入输出】为再筛选DataItem的地址,筛选条件[regex, (>x0; <x1)]
        * loc_[regex,_y0y1]    返回查找值是否为空, 第一个参数inout_ptr【输入输出】为再筛选DataItem的地址,筛选条件[regex, (>y0; <y1)]
        * loc_[regex,_x0y0]    返回查找值是否为空, 第一个参数inout_ptr【输入输出】为再筛选DataItem的地址,筛选条件[regex, (<x0; <y0)]
        * loc_[regex,_x1y1]    返回查找值是否为空, 第一个参数inout_ptr【输入输出】为再筛选DataItem的地址,筛选条件[regex, (>x1; >y1)]
        */

        template<Field field, auto... patterns>
        MAYBE_USE static bool loc2_regex(VecItemPtr &inout_ptr) {
            return ptr2_reg_impl_<field, patterns...>(inout_ptr);
        }

        /////////////////////////////////////////////////////////////
        ////				 再次对地址（所在的值）进行筛选
        ////////////////////////////////////////////////////////////

        template<Field field, auto... patterns>
        MAYBE_USE static bool
        loc2_regex_grate_strlen(VecItemPtr &inout_ptr, const int len) {
            return ptr2_reg_len_impl<field, patterns...>(inout_ptr, len, std::greater<>());
        }

        template<Field field, auto... patterns>
        MAYBE_USE static bool
        loc2_regex_equal_strlen(VecItemPtr &inout_ptr, const int len) {
            return ptr2_reg_len_impl<field, patterns...>(inout_ptr, len, std::equal_to<>());
        }

        template<Field field, auto... patterns>
        MAYBE_USE static bool
        loc2_regex_less_strlen(VecItemPtr &inout_ptr, const int len) {
            return ptr2_reg_len_impl<field, patterns...>(inout_ptr, len, std::less<>());
        }

        /////////////////////////////////////////////////////////////
        ////				 再次对地址（所在的值）进行筛选
        ////////////////////////////////////////////////////////////
        template<Field field, auto... patterns>
        MAYBE_USE static bool
        loc2_regex_xyxy(VecItemPtr &inout_ptr, int x0, int y0, int x1, int y1) {
            return ptr2_reg_condition<field, patterns...>(inout_ptr,
                                                          [x0, y0, x1, y1](const DataItem &item) noexcept {
                                                              return item.x0 > x0 && item.x1 < x1 && item.y0 > y0 &&
                                                                     item.y1 < y1;
                                                          });
        }


        template<Field field, auto... patterns>
        MAYBE_USE static bool
        loc2_regex_x0x1(VecItemPtr &inout_ptr, int x0, int x1) {
            return ptr2_reg_condition<field, patterns...>(inout_ptr,
                                                          [x0, x1](const DataItem &item) noexcept {
                                                              return item.x0 > x0 && item.x1 < x1;
                                                          });
        }

        template<Field field, auto... patterns>
        MAYBE_USE static bool
        loc2_regex_y0y1(VecItemPtr &inout_ptr, int y0, int y1) {
            return ptr2_reg_condition<field, patterns...>(inout_ptr,
                                                          [y0, y1](const DataItem &item) noexcept {
                                                              return item.y0 > y0 && item.y1 < y1;
                                                          });
        }

        template<Field field, auto... patterns>
        MAYBE_USE static bool
        loc2_regex_x0y0(VecItemPtr &inout_ptr, int x0, int y0) {
            return ptr2_reg_condition<field, patterns...>(inout_ptr,
                                                          [x0, y0](const DataItem &item) noexcept {
                                                              return item.x0 > x0 && item.y0 > y0;
                                                          });
        }

        template<Field field, auto... patterns>
        MAYBE_USE static bool
        loc2_regex_x1y1(VecItemPtr &inout_ptr, int x1, int y1) {
            return ptr2_reg_condition<field, patterns...>(inout_ptr,
                                                          [x1, y1](const DataItem &item) noexcept {
                                                              return item.x1 < x1 && item.y1 < y1;
                                                          });
        }

        MAYBE_USE static bool loc2_xyxy(VecItemPtr &inout_ptr, int x0, int y0, int x1, int y1) {
            return ptr2_xyxy(inout_ptr, [x0, y0, x1, y1](const DataItem &item) noexcept {
                return item.x0 > x0 && item.y0 > y0 && item.x1 < x1 && item.y1 < y1;
            });
        }

        MAYBE_USE static bool loc2_x0x1(VecItemPtr &inout_ptr, int x0, int x1) {
            return ptr2_xyxy(inout_ptr, [x0, x1](const DataItem &item) noexcept {
                return item.x0 > x0 && item.x1 < x1;
            });
        }

        MAYBE_USE static bool loc2_y0y1(VecItemPtr &inout_ptr, int y0, int y1) {
            return ptr2_xyxy(inout_ptr, [y0, y1](const DataItem &item) noexcept {
                return item.y0 > y0 && item.y1 < y1;
            });
        }

        MAYBE_USE static bool loc2_x0y0(VecItemPtr &inout_ptr, int x0, int y0) {
            return ptr2_xyxy(inout_ptr, [x0, y0](const DataItem &item) noexcept {
                return item.x0 > x0 && item.y0 > y0;
            });
        }

        MAYBE_USE static bool loc2_x1y1(VecItemPtr &inout_ptr, int x1, int y1) {
            return ptr2_xyxy(inout_ptr, [x1, y1](const DataItem &item) noexcept {
                return item.x1 < x1 && item.y1 < y1;
            });
        }

        MAYBE_USE static bool loc2_x0_less(VecItemPtr &inout_ptr, int len) {
            return ptr2_xyxy(inout_ptr, [len](const DataItem &item) noexcept { return item.x0 < len; });
        }

        MAYBE_USE static bool loc2_y0_less(VecItemPtr &inout_ptr, int len) {
            return ptr2_xyxy(inout_ptr, [len](const DataItem &item) noexcept { return item.y0 < len; });
        }

        MAYBE_USE static bool loc2_x0_grate(VecItemPtr &inout_ptr, int len) {
            return ptr2_xyxy(inout_ptr, [len](const DataItem &item) noexcept { return item.x0 > len; });
        }

        MAYBE_USE static bool loc2_y0_grate(VecItemPtr &inout_ptr, int len) {
            return ptr2_xyxy(inout_ptr, [len](const DataItem &item) noexcept { return item.y0 > len; });
        }

        MAYBE_USE static bool loc2_x1_grate(VecItemPtr &inout_ptr, int len) {
            return ptr2_xyxy(inout_ptr, [len](const DataItem &item) noexcept { return item.x1 > len; });
        }

        MAYBE_USE static bool loc2_y1_grate(VecItemPtr &inout_ptr, int len) {
            return ptr2_xyxy(inout_ptr, [len](const DataItem &item) noexcept { return item.y1 > len; });
        }

        MAYBE_USE static bool loc2_x1_less(VecItemPtr &inout_ptr, int len) {
            return ptr2_xyxy(inout_ptr, [len](const DataItem &item) noexcept { return item.x1 < len; });
        }

        MAYBE_USE static bool loc2_y1_less(VecItemPtr &inout_ptr, int len) {
            return ptr2_xyxy(inout_ptr, [len](const DataItem &item) noexcept { return item.y1 < len; });
        }

    private:
        /*   对筛选后的df再次筛选（直接对地址进行筛选，无关类，为静态函数）   */
        //////////////////////////////////////////////////////////////////
        static bool ptr2_xyxy(VecItemPtr& inout_ptr,
                              const std::function<bool(const DataItem&)>& condition);

        template<Field field, auto... patterns>
        MAYBE_USE static bool ptr2_reg_impl_(VecItemPtr &inout_ptr);

        template<Field field, auto... patterns>
        MAYBE_USE static bool ptr2_reg_len_impl(
            VecItemPtr &inout_ptr,
            int len,
            const std::function<bool(size_t, size_t)> &compare);

        template<Field field, auto... patterns>
        MAYBE_USE static bool ptr2_reg_condition(
            VecItemPtr &inout_ptr,
            const std::function<bool(const DataItem &)> &condition);
    };

    template<Field field>
    MAYBE_USE std::string join(UDataBase::VecItemPtr &in_ptr, const std::string &Char_ = std::string());

    template<Field field>
    MAYBE_USE constexpr auto getTextRefConst(const DataItem& item) -> const std::string& {
        if constexpr (field == Field::TEXT) {
            return item.text;
        } else if constexpr (field == Field::TEXT_SEP) {
            return item.text_sep;
        } else {
            static_assert(always_false<field>(false), "Invalid field");
            return item.text;
        }
    }


    template<Field field>
    MAYBE_USE constexpr auto getTextRef(DataItem& item) -> std::string& {
        if constexpr (field == Field::TEXT) {
            return item.text;
        } else if constexpr (field == Field::TEXT_SEP) {
            return item.text_sep;
        } else {
            static_assert(always_false<field>(false), "Invalid field");
            return item.text;
        }
    }

    template <auto pattern>
    std::string global_replace(std::string_view input, std::string_view rewrite);

    template <auto... patterns>
    bool matches_any(std::string_view text) {
        static_assert(sizeof...(patterns) > 0, "Must provide at least one pattern.");
        return (ctre::search<patterns>(text) || ...);
    }

    // 辅助函数：获取字符串在终端的视觉宽度
    size_t get_visual_width(const std::string& str);

    // 辅助函数：打印分隔线
    void print_separator(std::ostream& os, const std::vector<size_t>& widths, char separator);


    // 辅助函数：打印一行数据，并正确处理中英文对齐
    void print_row(std::ostream& os, const std::vector<size_t>& widths, const std::vector<std::string>& row_data);


    void format_print(const UDataBase& database);

	void format_print(const UDataBase* dataframe);

    void format_print(const std::vector<DataItem*>& pointers);

}

#include "UDataBase.inl"
#endif //UDATABASE_H
